/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/


#include <flgrCoreData.h>
#include <flgrCoreDataIO.h>
#include <flgrCoreShift.h>
#include <flgrCoreCopy.h>
#include <flgrCoreCompare.h>
#include <flgrCoreDispatch.h>
#include <flgrCoreVector.h>
#include <flgrCoreArithVector.h>
#include <flgrArith.h>
#include <flgrMeasureBase.h>
#include "flgrMorphoGeodesyFast.h"
#include "flgrMorphoBase.h"

/*!
 * \addtogroup group_fulguro_morpho_geo
 * @{
 */



#define FLGR_MACRO_LINE_ERODE(dtype,lout,lin,ltmp1,ltmp0)	\
  flgr1d_shift_right_##dtype(ltmp0,lin, 1, vec);		\
  flgr1d_shift_left_##dtype(ltmp1,lin, 1, vec);			\
  flgr1d_arith_inf_##dtype(ltmp0,ltmp1,ltmp0);			\
  flgr1d_arith_inf_##dtype(lout,lin,ltmp0) 
 
#define FLGR_MACRO_LINE_RIGHT_ERODE(dtype,lout,lin,ltmp0)	\
  flgr1d_shift_right_##dtype(ltmp0,lin, 1, vec);		\
  flgr1d_arith_inf_##dtype(lout,ltmp0,lin)

#define FLGR_MACRO_LINE_LEFT_ERODE(dtype,lout,lin,ltmp0)	\
  flgr1d_shift_left_##dtype(ltmp0,lin, 1, vec);			\
  flgr1d_arith_inf_##dtype(lout,ltmp0,lin)

#define FLGR_MACRO_GEODESIC_ERODE_8_CONNEXITY(dtype)			\
  FLGR_Data1D *tmpL0 = flgr1d_create_signal_from(datmask->row[0]);	\
  FLGR_Data1D *tmpL1 = flgr1d_create_signal_from(datmask->row[0]);	\
  FLGR_Data1D *tmp0 = flgr1d_create_signal_from(datmask->row[0]);	\
  FLGR_Data1D *tmp1 = flgr1d_create_signal_from(datmask->row[0]);	\
  FLGR_Data1D *tmp2 = flgr1d_create_signal_from(datmask->row[0]);	\
  FLGR_Data1D *tmpsav;							\
  FLGR_Data1D **pout = datmark->row;					\
  FLGR_Data1D **pin = datmark->row;					\
  FLGR_Data1D **pmask = datmask->row;					\
  FLGR_Vector *vec = flgr_vector_create(datmask->spp,datmask->type);	\
  dtype max = MAX_##dtype;						\
  int i,k,j;								\
  									\
  FLGR_DECLARE_FUNCTION;						\
  									\
  flgr_vector_populate_from_scalar_##dtype(vec,max);			\
									\
  FLGR_MACRO_LINE_ERODE(dtype,tmp0,pin[0],tmpL0,tmpL1);			\
  FLGR_MACRO_LINE_ERODE(dtype,tmp1,pin[1],tmpL0,tmpL1);			\
									\
  flgr1d_arith_inf_##dtype(pout[0],tmp0,tmp1);				\
  flgr1d_arith_sup_##dtype(pout[0],pmask[0],pout[0]);			\
  									\
  									\
  for(i=0,j=1,k=2 ; i<datmask->size_y-2 ; i++,j++,k++) {		\
    FLGR_MACRO_LINE_ERODE(dtype,tmp2,pin[k],tmpL0,tmpL1);		\
    flgr1d_arith_inf_##dtype(tmp0,tmp1,tmp0);				\
    flgr1d_arith_inf_##dtype(pout[j],tmp0,tmp2);			\
    flgr1d_arith_sup_##dtype(pout[j],pmask[j],pout[j]);			\
    									\
    tmpsav=tmp0;							\
    tmp0=tmp1;								\
    tmp1=tmp2;								\
    tmp2=tmpsav;							\
  }									\
									\
  j = datmask->size_y-1;						\
									\
  flgr1d_arith_inf_##dtype(pout[j],tmp0,tmp1);				\
  flgr1d_arith_sup_##dtype(pout[j],pmask[j],pout[j]);			\
  									\
  flgr_vector_destroy(vec);						\
  flgr1d_destroy(tmpL0);						\
  flgr1d_destroy(tmpL1);						\
  flgr1d_destroy(tmp0);							\
  flgr1d_destroy(tmp1);							\
  flgr1d_destroy(tmp2)



void flgr2d_geodesic_erode_8_connexity_fgBIT(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_ERODE_8_CONNEXITY(fgBIT);
}
void flgr2d_geodesic_erode_8_connexity_fgUINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_ERODE_8_CONNEXITY(fgUINT8);
}
void flgr2d_geodesic_erode_8_connexity_fgUINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_ERODE_8_CONNEXITY(fgUINT16);
}
void flgr2d_geodesic_erode_8_connexity_fgUINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_ERODE_8_CONNEXITY(fgUINT32);
}
void flgr2d_geodesic_erode_8_connexity_fgINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_ERODE_8_CONNEXITY(fgINT8);
}
void flgr2d_geodesic_erode_8_connexity_fgINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_ERODE_8_CONNEXITY(fgINT16);
}
void flgr2d_geodesic_erode_8_connexity_fgINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_ERODE_8_CONNEXITY(fgINT32);
}
void flgr2d_geodesic_erode_8_connexity_fgFLOAT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_ERODE_8_CONNEXITY(fgFLOAT32);
}
void flgr2d_geodesic_erode_8_connexity_fgFLOAT64(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_ERODE_8_CONNEXITY(fgFLOAT64);
}

FLGR_Ret flgr2d_geodesic_erode_8_connexity(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datmark==NULL) || (datmask==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datmask,datmark,__FUNCTION__))!=FLGR_RET_OK) return ret;
 
  FLGR_DISPATCH_PROCEDURE(datmask->type,flgr2d_geodesic_erode_8_connexity,datmark,datmask);

}


















#define FLGR_MACRO_LINE_DILATE(dtype,lout,lin,ltmp1,ltmp0)	\
  flgr1d_shift_right_##dtype(ltmp0,lin, 1,vec);			\
  flgr1d_shift_left_##dtype(ltmp1,lin, 1,vec);			\
  flgr1d_arith_sup_##dtype(ltmp0,ltmp1,ltmp0);			\
  flgr1d_arith_sup_##dtype(lout,lin,ltmp0) 
 
#define FLGR_MACRO_LINE_RIGHT_DILATE(dtype,lout,lin,ltmp0)	\
  flgr1d_shift_right_##dtype(ltmp0,lin, 1,vec);			\
  flgr1d_arith_sup_##dtype(lout,ltmp0,lin)

#define FLGR_MACRO_LINE_LEFT_DILATE(dtype,lout,lin,ltmp0)	\
  flgr1d_shift_left_##dtype(ltmp0,lin, 1,vec);			\
  flgr1d_arith_sup_##dtype(lout,ltmp0,lin)

#define FLGR_MACRO_GEODESIC_DILATE_8_CONNEXITY(dtype)			\
  FLGR_Data1D *tmpL0 = flgr1d_create_signal_from(datmask->row[0]);	\
  FLGR_Data1D *tmpL1 = flgr1d_create_signal_from(datmask->row[0]);	\
  FLGR_Data1D *tmp0 = flgr1d_create_signal_from(datmask->row[0]);	\
  FLGR_Data1D *tmp1 = flgr1d_create_signal_from(datmask->row[0]);	\
  FLGR_Data1D *tmp2 = flgr1d_create_signal_from(datmask->row[0]);	\
  FLGR_Data1D *tmpsav;							\
  FLGR_Data1D **pout = datmark->row;					\
  FLGR_Data1D **pin = datmark->row;					\
  FLGR_Data1D **pmask = datmask->row;					\
  FLGR_Vector *vec = flgr_vector_create(datmask->spp,datmask->type);	\
  dtype min = MIN_##dtype;						\
  int i,k,j;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  flgr_vector_populate_from_scalar_##dtype(vec,min);			\
									\
  FLGR_MACRO_LINE_DILATE(dtype,tmp0,pin[0],tmpL0,tmpL1);		\
  FLGR_MACRO_LINE_DILATE(dtype,tmp1,pin[1],tmpL0,tmpL1);		\
									\
  flgr1d_arith_sup_##dtype(pout[0],tmp0,tmp1);				\
  flgr1d_arith_inf_##dtype(pout[0],pmask[0],pout[0]);			\
  									\
  									\
  for(i=0,j=1,k=2 ; i<datmask->size_y-2 ; i++,j++,k++) {		\
    FLGR_MACRO_LINE_DILATE(dtype,tmp2,pin[k],tmpL0,tmpL1);		\
    flgr1d_arith_sup_##dtype(tmp0,tmp1,tmp0);				\
    flgr1d_arith_sup_##dtype(pout[j],tmp0,tmp2);			\
    flgr1d_arith_inf_##dtype(pout[j],pmask[j],pout[j]);			\
									\
    tmpsav=tmp0;							\
    tmp0=tmp1;								\
    tmp1=tmp2;								\
    tmp2=tmpsav;							\
  }									\
									\
  j = datmask->size_y-1;						\
									\
  flgr1d_arith_sup_##dtype(pout[j],tmp0,tmp1);				\
  flgr1d_arith_inf_##dtype(pout[j],pmask[j],pout[j]);			\
  									\
  flgr_vector_destroy(vec);						\
  flgr1d_destroy(tmpL0);						\
  flgr1d_destroy(tmpL1);						\
  flgr1d_destroy(tmp0);							\
  flgr1d_destroy(tmp1);							\
  flgr1d_destroy(tmp2)



void flgr2d_geodesic_dilate_8_connexity_fgBIT(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_DILATE_8_CONNEXITY(fgBIT);
}
void flgr2d_geodesic_dilate_8_connexity_fgUINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_DILATE_8_CONNEXITY(fgUINT8);
}
void flgr2d_geodesic_dilate_8_connexity_fgUINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_DILATE_8_CONNEXITY(fgUINT16);
}
void flgr2d_geodesic_dilate_8_connexity_fgUINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_DILATE_8_CONNEXITY(fgUINT32);
}
void flgr2d_geodesic_dilate_8_connexity_fgINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_DILATE_8_CONNEXITY(fgINT8);
}
void flgr2d_geodesic_dilate_8_connexity_fgINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_DILATE_8_CONNEXITY(fgINT16);
}
void flgr2d_geodesic_dilate_8_connexity_fgINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_DILATE_8_CONNEXITY(fgINT32);
}
void flgr2d_geodesic_dilate_8_connexity_fgFLOAT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_DILATE_8_CONNEXITY(fgFLOAT32);
}
void flgr2d_geodesic_dilate_8_connexity_fgFLOAT64(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_MACRO_GEODESIC_DILATE_8_CONNEXITY(fgFLOAT64);
}

FLGR_Ret flgr2d_geodesic_dilate_8_connexity(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datmark==NULL) || (datmask==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datmask,datmark,__FUNCTION__))!=FLGR_RET_OK) return ret;
 
  FLGR_DISPATCH_PROCEDURE(datmask->type,flgr2d_geodesic_dilate_8_connexity,datmark,datmask);

}








#define FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL_8_CONNEXITY(dtype)		\
  FLGR_Data2D *tmp = flgr2d_create_pixmap_from(datmark);		\
									\
  do{									\
    flgr2d_copy_##dtype##_##dtype(tmp,datmark);				\
    flgr2d_geodesic_dilate_8_connexity_##dtype(datmark,datmask);	\
  }while(flgr2d_compare_##dtype(tmp,FLGR_TEST_EQ,datmark) !=FLGR_TRUE); \
									\
  flgr2d_destroy(tmp)


void flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgBIT(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL_8_CONNEXITY(fgBIT);
}
void flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgUINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL_8_CONNEXITY(fgUINT8);
}
void flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgUINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL_8_CONNEXITY(fgUINT16);
}
void flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgUINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL_8_CONNEXITY(fgUINT32);
}
void flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL_8_CONNEXITY(fgINT8);
}
void flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL_8_CONNEXITY(fgINT16);
}
void flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL_8_CONNEXITY(fgINT32);
}
void flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgFLOAT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL_8_CONNEXITY(fgFLOAT32);
}
void flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgFLOAT64(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL_8_CONNEXITY(fgFLOAT64);
}









#define FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL_8_CONNEXITY(dtype)		\
  FLGR_Data2D *tmp = flgr2d_create_pixmap_from(datmark);		\
									\
  do{									\
    flgr2d_copy_##dtype##_##dtype(tmp,datmark);				\
    flgr2d_geodesic_erode_8_connexity_##dtype(datmark,datmask);		\
  }while(flgr2d_compare_##dtype(tmp,FLGR_TEST_EQ,datmark) !=FLGR_TRUE); \
									\
  flgr2d_destroy(tmp)


void flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgBIT(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL_8_CONNEXITY(fgBIT);
}
void flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgUINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL_8_CONNEXITY(fgUINT8);
}
void flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgUINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL_8_CONNEXITY(fgUINT16);
}
void flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgUINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL_8_CONNEXITY(fgUINT32);
}
void flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL_8_CONNEXITY(fgINT8);
}
void flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL_8_CONNEXITY(fgINT16);
}
void flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL_8_CONNEXITY(fgINT32);
}
void flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgFLOAT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL_8_CONNEXITY(fgFLOAT32);
}
void flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgFLOAT64(FLGR_Data2D *datmark, FLGR_Data2D *datmask) {
  FLGR_DECLARE_FUNCTION;
  FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL_8_CONNEXITY(fgFLOAT64);
}
































#define FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL(dtype)			\
  FLGR_Data2D *tmp = flgr2d_create_pixmap_from(datmark);		\
  FLGR_Data2D *nhb =							\
    flgr2d_create_neighborhood_from_connexity(datmask->spp,		\
					      datmask->type,connexity); \
									\
  do{									\
    flgr2d_copy_##dtype##_##dtype(tmp,datmark);				\
    flgr2d_dilate_##dtype(datmark,tmp,nhb);				\
    flgr2d_arith_inf_##dtype(datmark,datmark,datmask);			\
  }while(flgr2d_compare_##dtype(tmp,FLGR_TEST_EQ,datmark) !=FLGR_TRUE); \
									\
  flgr2d_destroy(tmp);							\
  flgr2d_destroy(nhb)



void flgr2d_geodesic_reconstruct_dilate_parallel_fgBIT(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgBIT(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL(fgBIT);
  }
}
void flgr2d_geodesic_reconstruct_dilate_parallel_fgUINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgUINT8(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL(fgUINT8);
  }
}
void flgr2d_geodesic_reconstruct_dilate_parallel_fgUINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgUINT16(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL(fgUINT16);
  }
}
void flgr2d_geodesic_reconstruct_dilate_parallel_fgUINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgUINT32(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL(fgUINT32);
  }
}
void flgr2d_geodesic_reconstruct_dilate_parallel_fgINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgINT8(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL(fgINT8);
  }
}
void flgr2d_geodesic_reconstruct_dilate_parallel_fgINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgINT16(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL(fgINT16);
  }
}
void flgr2d_geodesic_reconstruct_dilate_parallel_fgINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgINT32(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL(fgINT32);
  }
}
void flgr2d_geodesic_reconstruct_dilate_parallel_fgFLOAT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgFLOAT32(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL(fgFLOAT32);
  }
}
void flgr2d_geodesic_reconstruct_dilate_parallel_fgFLOAT64(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_dilate_parallel_8_connexity_fgFLOAT64(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_DIL_PARALLEL(fgFLOAT64);
  }
}




////////////////////////////////////////////////////////////////////////////
/*! Compute Geodesic Reconstruction by Dilation (parallel version using exactly mathematical definition) 
 *  @param imgMarker : marker image input / output
 *  @param imgMask : mask image input
 *  @param connexity : connexity to use (FLGR_4_CONNEX, ...)
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_geodesic_reconstruct_dilate_parallel(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_Ret ret;
  
  FLGR_DECLARE_FUNCTION;

  if((datmark==NULL) || (datmask==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datmask,datmark,__FUNCTION__))!=FLGR_RET_OK) return ret;
 
  FLGR_DISPATCH_PROCEDURE(datmask->type,flgr2d_geodesic_reconstruct_dilate_parallel,datmark,datmask,connexity);
}

















#define FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL(dtype)			\
  FLGR_Data2D *tmp = flgr2d_create_pixmap_from(datmark);		\
  FLGR_Data2D *nhb =							\
    flgr2d_create_neighborhood_from_connexity(datmask->spp,		\
					      datmask->type,connexity); \
									\
  do{									\
    flgr2d_copy_##dtype##_##dtype(tmp,datmark);				\
    flgr2d_erode_##dtype(datmark,tmp,nhb);				\
    flgr2d_arith_sup_##dtype(datmark,datmark,datmask);			\
  }while(flgr2d_compare_##dtype(tmp,FLGR_TEST_EQ,datmark) !=FLGR_TRUE); \
									\
  flgr2d_destroy(tmp);							\
  flgr2d_destroy(nhb)



void flgr2d_geodesic_reconstruct_erode_parallel_fgBIT(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgBIT(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL(fgBIT);
  }
}
void flgr2d_geodesic_reconstruct_erode_parallel_fgUINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgUINT8(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL(fgUINT8);
  }
}
void flgr2d_geodesic_reconstruct_erode_parallel_fgUINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgUINT16(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL(fgUINT16);
  }
}
void flgr2d_geodesic_reconstruct_erode_parallel_fgUINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgUINT32(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL(fgUINT32);
  }
}
void flgr2d_geodesic_reconstruct_erode_parallel_fgINT8(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgINT8(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL(fgINT8);
  }
}
void flgr2d_geodesic_reconstruct_erode_parallel_fgINT16(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgINT16(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL(fgINT16);
  }
}
void flgr2d_geodesic_reconstruct_erode_parallel_fgINT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgINT32(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL(fgINT32);
  }
}
void flgr2d_geodesic_reconstruct_erode_parallel_fgFLOAT32(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgFLOAT32(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL(fgFLOAT32);
  }
}
void flgr2d_geodesic_reconstruct_erode_parallel_fgFLOAT64(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_DECLARE_FUNCTION;
  if(connexity == FLGR_8_CONNEX) {
    flgr2d_geodesic_reconstruct_erode_parallel_8_connexity_fgFLOAT64(datmark,datmask);
  }else {
    FLGR_MACRO_2D_GEO_REC_ERO_PARALLEL(fgFLOAT64);
  }
}




////////////////////////////////////////////////////////////////////////////
/*! Compute Geodesic Reconstruction by Erosion (parallel version using exactly mathematical definition) 
 *  @param imgMarker : marker image input / output
 *  @param imgMask : mask image input
 *  @param connexity : connexity to use (FLGR_4_CONNEX, ...)
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_geodesic_reconstruct_erode_parallel(FLGR_Data2D *datmark, FLGR_Data2D *datmask, FLGR_Connexity connexity) {
  FLGR_Ret ret;
  
  FLGR_DECLARE_FUNCTION;

  if((datmark==NULL) || (datmask==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret=flgr2d_is_data_same_attributes(datmask,datmark,__FUNCTION__))!=FLGR_RET_OK) return ret;
 
  FLGR_DISPATCH_PROCEDURE(datmask->type,flgr2d_geodesic_reconstruct_erode_parallel,datmark,datmask,connexity);
}


////////////////////////////////////////////////////////////////////////////
/*! Compute Geodesic Reconstruction by openning (parallel version using exactly mathematical definition)
 *  @param imgdest : output image
 *  @param imgsrc : input input
 *  @param nhb : neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_geodesic_reconstruct_open_parallel(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL) ||(nhb==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if( (ret=flgr2d_erode(imgdest,imgsrc,nhb)) != FLGR_RET_OK ) return ret;

  return flgr2d_geodesic_reconstruct_dilate_parallel(imgdest,imgsrc,nhb->connexity);
}

////////////////////////////////////////////////////////////////////////////
/*! Compute Geodesic Reconstruction by closeing (parallel version using exactly mathematical definition)
 *  @param imgdest : output image
 *  @param imgsrc : input input
 *  @param nhb : neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_geodesic_reconstruct_close_parallel(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL) || (nhb==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if( (ret=flgr2d_dilate(imgdest,imgsrc,nhb)) != FLGR_RET_OK ) return ret;

  return flgr2d_geodesic_reconstruct_erode_parallel(imgdest,imgsrc,nhb->connexity);
}

////////////////////////////////////////////////////////////////////////////
/*! Compute Geodesic Open Tophat (parallel version using exactly mathematical definition)
 *  @param imgdest : output image
 *  @param imgsrc : input input
 *  @param nhb : neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_geodesic_reconstruct_open_tophat_parallel(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL) ||(nhb==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if( (ret=flgr2d_geodesic_reconstruct_open_parallel(imgdest,imgsrc,nhb)) != FLGR_RET_OK ) return ret;

  return flgr2d_arith_sub(imgdest,imgsrc,imgdest);
}

////////////////////////////////////////////////////////////////////////////
/*! Compute Geodesic Close Tophat (parallel version using exactly mathematical definition)
 *  @param imgdest : output image
 *  @param imgsrc : input input
 *  @param nhb : neighborhood definition
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_geodesic_reconstruct_close_tophat_parallel(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL) || (nhb==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if( (ret=flgr2d_geodesic_reconstruct_close_parallel(imgdest,imgsrc,nhb)) != FLGR_RET_OK ) return ret;

  return flgr2d_arith_sub(imgdest,imgdest,imgsrc);
}





////////////////////////////////////////////////////////////////////////////
/*! Compute Regional H-Minima (parallel version using exactly mathematical definition)
 *  @param imgdest : output image
 *  @param imgsrc : input input
 *  @param hlevel : level of the minima
 *  @param connexity : string for connexity to use
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_regional_hminima_parallel(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Vector *hlevel, FLGR_Connexity connexity) {
  FLGR_Ret ret;
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  imgtmp = flgr2d_create_pixmap_from(imgsrc);
  if(imgtmp == NULL) {
    POST_ERROR("Could not allocate image \n");
    return FLGR_RET_ALLOCATION_ERROR;
  }


  if( (ret=flgr2d_arith_const_addsat_ptr(imgtmp,imgsrc,hlevel)) != FLGR_RET_OK ) return ret;
  if( (ret=flgr2d_geodesic_reconstruct_erode_parallel(imgtmp,imgsrc,connexity)) != FLGR_RET_OK ) return ret;

  ret = flgr2d_arith_sub(imgdest,imgtmp,imgsrc);

  flgr2d_destroy(imgtmp);

  return ret;

}



////////////////////////////////////////////////////////////////////////////
/*! Compute Regional H-Maxima (parallel version using exactly mathematical definition)
 *  @param imgdest : output image
 *  @param imgsrc : input input
 *  @param hlevel : level of the maxima
 *  @param connexity : string for connexity to use
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_regional_hmaxima_parallel(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Vector *hlevel, FLGR_Connexity connexity) {
  FLGR_Ret ret;
  FLGR_Data2D *imgtmp;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  imgtmp = flgr2d_create_pixmap_from(imgsrc);
  if(imgtmp == NULL) {
    POST_ERROR("Could not allocate image \n");
    return FLGR_RET_ALLOCATION_ERROR;
  }


  if( (ret=flgr2d_arith_const_subsat_ptr(imgtmp,imgsrc,hlevel)) != FLGR_RET_OK ) return ret;
  if( (ret=flgr2d_geodesic_reconstruct_dilate_parallel(imgtmp,imgsrc,connexity)) != FLGR_RET_OK ) return ret;

  ret = flgr2d_arith_sub(imgdest,imgsrc,imgtmp);

  flgr2d_destroy(imgtmp);

  return ret;

}







//! @}





